﻿using System;
using System.Timers;
using System.Web.Caching;
using Microsoft.SharePoint;
using Redirection.Helpers;

namespace Redirection
{
    public class SPListCacheDependency : CacheDependency
    {
        private readonly SPListCacheDependencyEventArgs _eventArgs;
        private readonly int _itemCount;
        private readonly DateTime _lastModified;
        private readonly Timer _timer;
        private readonly string _uniqueId;

        public SPListCacheDependency(SPList list)
            : this(list, 10000)
        {
        }

        public SPListCacheDependency(SPList list, double interval)
        {
            _lastModified = list.LastItemModifiedDate;
            if (list.LastItemDeletedDate > _lastModified)
            {
                _lastModified = list.LastItemDeletedDate;
            }

            _itemCount = list.ItemCount;
            _uniqueId = list.ID.ToString() + list.ParentWeb.ID + list.ParentWeb.Site.ID;
            _eventArgs = new SPListCacheDependencyEventArgs(list.ParentWeb.Site.ID, list.ParentWeb.ID, list.ID);
            _timer = new Timer(interval) {AutoReset = true}; // check every ten second
            _timer.Elapsed += MonitorChanges;
            _timer.Start();
        }

        public override string GetUniqueID()
        {
            return _uniqueId;
        }

        public bool HasObjectChanged(object source)
        {
            var list = source as SPList;
            if (list == null) return false;

            var modified = ListHelper.LastModified(list);

            return _lastModified != modified || _itemCount != list.ItemCount;
        }

        private void MonitorChanges(object sender, ElapsedEventArgs e)
        {
            try
            {
                SPSecurity.RunWithElevatedPrivileges(delegate
                    {
                        using (var site = new SPSite(_eventArgs.SiteId))
                        {
                            using (var web = site.OpenWeb(_eventArgs.WebId))
                            {
                                try
                                {
                                    var list = web.Lists[_eventArgs.ListId];
                                    ObjectChanged(list);
                                }
                                catch (SPException)
                                {
                                    _timer.Stop();
                                }
                            }
                        }
                    });
            }
            catch (ArgumentException)
            {
                //Object has been deleted.
                ObjectChanged(null);
            }
        }

        /// <summary>
        ///     Raise event and stop timer if object has been updated
        /// </summary>
        /// <param name="item"></param>
        private void ObjectChanged(object item)
        {
            if (!HasObjectChanged(item) && item != null) return;

            _timer.Stop();
            NotifyDependencyChanged(this, _eventArgs);
        }
    }
}